/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict'

angular.module('flowableApp').controller('TasksController', [
  '$rootScope',
  '$scope',
  '$translate',
  '$http',
  '$timeout',
  '$location',
  '$modal',
  '$popover',
  'appResourceRoot',
  'CommentService',
  'TaskService',
  '$routeParams',
  'AppDefinitionService',
  function(
    $rootScope,
    $scope,
    $translate,
    $http,
    $timeout,
    $location,
    $modal,
    $popover,
    appResourceRoot,
    CommentService,
    TaskService,
    $routeParams,
    AppDefinitionService
  ) {
    // Ensure correct main page is set
    $rootScope.setMainPageById('tasks')

    $scope.model = {
      page: 0,
      initialLoad: false
    }

    // Init sort options
    $scope.model.sorts = [
      { id: 'created-desc', title: 'TASK.FILTER.CREATED-DESC' },
      { id: 'created-asc', title: 'TASK.FILTER.CREATED-ASC' },
      { id: 'due-desc', title: 'TASK.FILTER.DUE-DESC' },
      { id: 'due-asc', title: 'TASK.FILTER.DUE-ASC' }
    ]

    // Init state options
    $scope.model.stateFilterOptions = [
      { id: 'open', title: 'TASK.FILTER.STATE-OPEN' },
      { id: 'completed', title: 'TASK.FILTER.STATE-COMPLETED' }
    ]

    // Init assignment options
    $scope.model.assignmentOptions = [
      { id: 'involved', title: $translate.instant('TASK.FILTER.ASSIGNMENT-INVOLVED') },
      { id: 'assignee', title: $translate.instant('TASK.FILTER.ASSIGNMENT-ASSIGNEE') },
      { id: 'candidate', title: $translate.instant('TASK.FILTER.ASSIGNMENT-CANDIDATE') }
    ]

    if ($scope.account && $scope.account.groups && $scope.account.groups.length > 0) {
      for (var i = 0; i < $scope.account.groups.length; i++) {
        if ($scope.account.groups[i].type == 1) {
          $scope.model.assignmentOptions.push({
            id: 'group_' + $scope.account.groups[i].id,
            title: $translate.instant('TASK.FILTER.ASSIGNMENT-GROUP', $scope.account.groups[i])
          })
        }
      }
    }

    // Sets defaults for all filters
    $scope.resetFilters = function(forcePropagateToRootScope) {
      $scope.model.page = 0

      // Init empty filter model
      $scope.model.filter = {
        loading: false,
        expanded: false,
        param: {
          state: $scope.model.stateFilterOptions[0],
          nonDefaultFilter: false
        }
      }

      // Defaults
      $scope.model.filter.param.sort = $scope.model.sorts[0].id
      $scope.model.filter.param.assignment = $scope.model.assignmentOptions[0].id
      $scope.model.filter.param.processDefinitionId = 'default'

      $scope.appDefinitionKey = $routeParams.appDefinitionKey
      $scope.missingAppdefinition = $scope.appDefinitionKey === false

      // In case of viewing tasks in an app-context, need to make filter aware of this
      $scope.model.filter.param.appDefinitionKey = $scope.appDefinitionKey

      // Propagate to root filter
      if (
        forcePropagateToRootScope === true ||
        ($rootScope.taskFilter === null && $rootScope.taskFilter === undefined)
      ) {
        $rootScope.taskFilter = { param: $scope.model.filter.param }
      }
    }

    $scope.resetFilters() // First time: init defaults

    // The filter is stored on the rootScope, which allows the user to switch back and forth without losing the filter.
    if ($rootScope.taskFilter !== null && $rootScope.taskFilter !== undefined) {
      $scope.model.filter.param = $rootScope.taskFilter.param
    } else {
      $rootScope.taskFilter = { param: $scope.model.filter.param }
    }

    // Update app on rootScope. If app id present, it will fetch definition if not already fetched to update view and navigation accordingly
    AppDefinitionService.setActiveAppDefinitionKey($scope.appDefinitionKey)

    // Callback for state selection widget
    $scope.selectStateFilter = function(state) {
      if (state !== $scope.model.filter.param.state) {
        $scope.model.filter.param.state = state
        $scope.collapseFilter()
        $scope.resetPaging()
        $scope.refreshFilter()
      }
    }

    $scope.sortChanged = function() {
      $scope.resetPaging()
      $scope.refreshFilter()
    }

    $scope.nextPage = function() {
      $scope.model.page = $scope.model.page + 1
      $scope.refreshFilter()
    }

    $scope.resetPaging = function() {
      $scope.model.page = 0
    }

    $scope.refreshFilter = function() {
      $scope.model.filter.loading = true

      var params = $scope.model.filter.param
      params.nonDefaultFilter = false

      // Assignee
      var data = {
        assignee: $rootScope.account.id,
        page: $scope.model.page
      }

      // Text filter
      if (params.text) {
        data.text = params.text
        params.nonDefaultFilter = true
      }

      // State folder
      if (params.state) {
        data.state = params.state.id

        if (params.state.id !== 'open') {
          params.nonDefaultFilter = true
        }
      }

      // Assignment
      if (params.assignment) {
        data.assignment = params.assignment

        if (params.assignment !== 'involved') {
          params.nonDefaultFilter = true
        }
      }

      // Process definition
      if (params.processDefinitionId && params.processDefinitionId !== 'default') {
        // default = empty choice
        data.processDefinitionId = params.processDefinitionId
        params.nonDefaultFilter = true
      }

      // App definition
      if (params.appDefinitionKey) {
        data.appDefinitionKey = params.appDefinitionKey
      }

      // Sort order
      data.sort = params.sort

      TaskService.queryTasks(data).then(function(response) {
        $scope.model.filter.loading = false

        if (response.start === 0) {
          $scope.model.tasks = response.data

          if ((!response.data || response.data.length == 0) && !params.nonDefaultFilter) {
            $scope.state = { noOwnTasks: true }
          } else {
            $scope.state = { noOwnTasks: false }
          }

          $scope.selectedTask = $scope.model.tasks[0]
        } else {
          for (var taskIndex = 0; taskIndex < response.data.length; taskIndex++) {
            $scope.model.tasks.push(response.data[taskIndex])
          }
          $scope.state = { noOwnTasks: false }

          if (!$scope.selectedTask) {
            $scope.selectedTask = response.data[0]
          }
        }
        $scope.model.hasNextPage = response.start + response.size < response.total

        // If coming from the process page the root.selectedTaskId will be set
        var taskIsPartOfCurrentList = false
        if ($rootScope.root.selectedTaskId) {
          for (var i = 0; i < response.data.length; i++) {
            if (response.data[i].id == $rootScope.root.selectedTaskId) {
              taskIsPartOfCurrentList = true
              $scope.selectedTask = response.data[i]
              break
            }
          }

          // if the task isn't part of the currently showed list,
          // the details are still shown
          if (!taskIsPartOfCurrentList) {
            // This is kinda cheating, but this way no additional fetch is needed
            $scope.selectedTask = { id: $rootScope.root.selectedTaskId }
          }

          // Always remove the root task id when it was used (otherwise will screw up next calls)
          $rootScope.root.selectedTaskId = undefined
        } else {
          if (!$scope.selectedTask) {
            $scope.selectedTask = $scope.model.tasks[0]
          }
        }
      })
    }

    $scope.selectTask = function(task) {
      $scope.selectedTask = task
    }

    $scope.createTask = function() {
      // Create popover
      if (!$scope.createTaskPopover) {
        $scope.newTask = {
          name: 'New task'
        }

        $scope.createTaskPopover = $popover(angular.element('#toggle-create-task'), {
          template: appResourceRoot + 'views/popover/create-task-popover.html',
          placement: 'bottom-left',
          show: true,
          scope: $scope
        })

        $scope.createTaskPopover.$scope.$on('tooltip.hide', function() {
          $scope.createTaskPopover.$scope.$destroy()
          $scope.createTaskPopover.destroy()
          $scope.createTaskPopover = undefined

          $scope.newTask = undefined
        })
      }
    }

    $scope.setTaskAssignee = function(user) {
      $scope.newTask.assignee = user
    }

    $scope.confirmTaskCreation = function(newTask) {
      if (!newTask) {
        newTask = $scope.newTask
      }
      if (newTask && newTask.name) {
        var taskData = {
          name: newTask.name,
          description: newTask.description
        }

        if (newTask.assignee && newTask.assignee.id) {
          taskData.assignee = newTask.assignee.id
        }

        if ($rootScope.activeAppDefinition) {
          taskData.category = '' + $rootScope.activeAppDefinition.id
        }

        newTask.loading = true
        TaskService.createTask(taskData).then(function(task) {
          newTask.loading = false

          if ($scope.createTaskPopover) {
            $scope.createTaskPopover.$scope.$destroy()
            $scope.createTaskPopover.destroy()
            $scope.createTaskPopover = undefined
          }

          $rootScope.addAlertPromise($translate('TASK.ALERT.CREATED', task))
        })
      }
    }

    $scope.expandFilter = function() {
      $scope.model.filter.expanded = true
    }

    $scope.collapseFilter = function() {
      $scope.model.filter.expanded = false
    }

    $scope.$on('task-completed', function(event, data) {
      $rootScope.addAlertPromise($translate('TASK.ALERT.COMPLETED', data))
      if (data && data.taskId == $scope.selectedTask.id) {
        // Current task has been completed. Refresh the filter
        $scope.selectedTask = undefined
        $scope.resetPaging()
        $scope.refreshFilter()
      }
    })

    $scope.$on('task-saved', function(event, data) {
      $rootScope.addAlertPromise($translate('TASK.ALERT.SAVED', data))
    })

    $scope.$on('task-completed-error', function(event, data) {
      $rootScope.addAlert(data.error.message, 'error')
    })

    $scope.$on('task-save-error', function(event, data) {
      $rootScope.addAlert(data.error.message, 'error')
    })

    // Refreshing list when new task is created
    $scope.$on('new-task-created', function(event, task) {
      // New tasks should always be on top, hence the sorting is set to last created
      $scope.resetFilters(true)
      $scope.resetPaging()
      $scope.refreshFilter()
    })

    // Load process definitions for the filter dropdown
    $rootScope.loadProcessDefinitions($scope.appDefinitionKey)

    // Add a watch, so we can
    var unregisterWatch = $scope.$watch('root.processDefinitions', function(data) {
      if (data !== null && data != undefined && data.length > 0) {
        var processDefinitions = data
        processDefinitions.splice(0, 0, { id: 'default', name: '' })
        $scope.model.processDefinitions = processDefinitions
        unregisterWatch()
      }
    })

    // Initial load
    if (!$rootScope.account) {
      window.$tokenProcess($http)
      $http
        .get(FLOWABLE.CONFIG.modelerContexRoot + '/app/rest/currentAccount')
        .success(function(data, status, headers, config) {
          $rootScope.account = data
          $rootScope.invalidCredentials = false
          $scope.refreshFilter()
        })
    } else {
      $scope.refreshFilter()
    }
  }
])
